﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace St0rm.IRCPro.Client {
    /// <summary>
    /// A Channel
    /// </summary>
    public class Channel {

        private string _name, _key = "";
        private int _limit = 0;

        private List<User> _users = new List<User>();
        
        private Client _client = new Client();

        private Dictionary<User, ChannelAccess> _access = new Dictionary<User, ChannelAccess>();

        /// <summary>
        /// Get list of Channels
        /// </summary>
        public static Channel[] Channels {
            get {
                return channels.ToArray();
            }
        }


        /// <summary>
        /// Gets the Name of this channel
        /// </summary>
        public string Name {
            get {
                return _name;
            }
        }

        /// <summary>
        /// Gets the Key of this channel
        /// </summary>
        public string Key {
            get {
                return _key;
            }
        }

        /// <summary>
        /// Gets the user limit in this channel. 0 means unlimited
        /// </summary>
        public int Limit {
            get {
                return _limit;
            }
        }

        /// <summary>
        /// Gets if the channel is in the internal list of channels. Use AddMe or DelMe to change
        /// </summary>
        public bool IsInList {
            get {
                return channels.Contains(this);
            }
        }

        /// <summary>
        /// Gets the Client this channel is on
        /// </summary>
        public Client Client {
            get {
                return _client;
            }
        }

        private Channel(string name, Client clnt) {
            _name = name;
            _client = clnt;
        }

        static List<Channel> channels = new List<Channel>();

        /// <summary>
        /// Gets the channel with the specified name.   
        /// </summary>
        /// <param name="name">Name of channel</param>
        /// <param name="clnt">Client channel is on</param>
        /// <returns>Channel</returns>
        public static Channel GetChannel(string name, Client clnt) {
            lock (channels) {

                foreach (Channel c in channels) {
                    if (clnt == c.Client && String.Compare(c.Name, name, true) == 0)
                    {
                        return c;
                    }
                }
             
            }
            return new Channel(name, clnt);
        }
        /// <summary>
        /// Adds to channellist
        /// </summary>
        public void AddMe() {
            lock (channels) {
                if (!channels.Contains(this))
                    channels.Add(this);
            }
        }
        /// <summary>
        /// Removes from channel list
        /// </summary>
        public void DelMe() {
            lock (channels) {
                if (channels.Contains(this))
                    channels.Remove(this);
            }
        }
        /// <summary>
        /// Returns the channel's name
        /// </summary>
        /// <returns>Channel name</returns>
        public override string ToString() {
            return Name;
        }
        /// <summary>
        /// Adds a user to the internal userlist
        /// </summary>
        /// <param name="u">User to add</param>
        public void AddUser(User u) {
            lock (_users) {
                if (!_users.Contains(u))
                    _users.Add(u);
            }
            
        }
        /// <summary>
        /// Sets access of user on channel
        /// </summary>
        /// <param name="u">User to set access of</param>
        /// <param name="a">Access to give user</param>
        public void SetAccess(User u, ChannelAccess a) {
            lock (_access) {
                if (_access.ContainsKey(u))
                    _access.Remove(u);
                _access.Add(u, a);
                
                    
            }
        }
        /// <summary>
        /// Gets access of user on channel
        /// </summary>
        /// <param name="u">User</param>
        /// <returns>Access</returns>
        public ChannelAccess GetAccess(User u) {
            ChannelAccess a;
            lock (_access) {
                _access.TryGetValue(u, out a);
            }
            if (a == null)
                a = new ChannelAccess("", _client);
            return a;
        }
        /// <summary>
        /// Removes a user to the internal userlist
        /// </summary>
        /// <param name="u">User to Remove</param>
        public void DelUser(User u) {
            lock (_users) {
                if (_users.Contains(u))
                    _users.Remove(u);
            }
        }
        /// <summary>
        /// Returns list of users on channel
        /// </summary>
        /// <returns></returns>
        public User[] GetUsers() {
            lock (_users) {
                return _users.ToArray();
            }
        }

        /// <summary>
        /// Sends a message to this channel
        /// </summary>
        /// <param name="message">message to send</param>
        public void SendMessage(string message) {
            Client.Send("PRIVMSG {0} :{1}", Name, message);
        }
        /// <summary>
        /// Sends a formatted message to this channel
        /// </summary>
        /// <param name="format">Format</param>
        /// <param name="arg">Format Arguments</param>
        public void SendMessage(string format, params object[] arg) {
            SendMessage(String.Format(format, arg));
            
        }
        
    }
}
